import { Component, ViewChild } from '@angular/core';
import { NavController, AlertController, Nav, NavParams, Slides } from 'ionic-angular';
import { RestService } from '../../app/services/rest.service';
import { TranslateService } from '@ngx-translate/core';
import { AlarmPage } from '../alarm/alarm';

import * as _ from 'lodash';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
  @ViewChild(Slides) slides: Slides;

  user: any;

  person: any;
  persons: any;

  moveTotal = '-';
  breatheAlarmTotal = '-';
  heartAlarmTotal = '-';
  awayAlarmTotal = '-';
  wetAlarmTotal = '-';

  heart = '-';
  breathe = '-';
  sleepScore = 0;
  sleepAdjustment = '';
  sleepDisplay: any;

  SHALLOW_SLEEP_MODE = "1";
  DEEP_SLEEP_MODE = "2";
  deepSleep = 0;
  shallowSleep = 0;
  totalSleep = 0;

  interval;
  options: any;

  bChartOptions;
  bEchartsInstance;

  hChartOptions;
  hEchartsInstance;

  moveChartOptions;
  moveChartsInstance;
  moveTitle;

  constructor(private rest: RestService,
              private translate: TranslateService,
              public alertCtrl: AlertController,
              public nav: Nav,
              public navParams: NavParams,
              public navCtrl: NavController) {
    this.user = this.rest.getUser();
    this.person = navParams.data.person;
    this.persons = navParams.data.persons;

    this.moveTitle = this.translate.get('moveTitle')['value'];
    this.options = {
      title: {
        text: '',
        subtext: '',
        subtextStyle: {color: 'black'},
        x: 'center',
        y: 'top',
        textStyle: {
          color: 'darkblue'
        },
      },
      tooltip: {
        trigger: 'axis',
      },
      grid: {
        x: '15px',
        y: '10px',
        x2: '18px',
        y2: '10px',
        containLabel: true
      },
      xAxis: {
        type: 'time',
        splitLine: {
          show: true
        }
      },
      yAxis: {
        type : 'value',
        boundaryGap: false,
        splitLine: {
          show: true
        }
      },
      series: [{
        type: 'line',
        showSymbol: false,
        markLine: {
          itemStyle: {
            normal: {
              lineStyle: {
                type: 'dashed',
                color: 'darkred'
              }
            }
          },
          data: []
        },
        data: []
      }]
    };

    this.initChart();
  }

  initChart() {
    const bSubtext = this.translate.get('heartUnit')['value'];
    this.bChartOptions = _.cloneDeep(this.options);
    this.bChartOptions.series[0].markLine.data = [
      {name: 'upper', yAxis: this.person.breatheUp},
      {name: 'lower', yAxis: this.person.breatheLow},
    ];
    this.bChartOptions.tooltip.formatter = (params) => {
      return new Date(params[0].data[0]).toLocaleString() + '<br>' + params[0].data[1] + ' ' + bSubtext;
    };

    this.hChartOptions = _.cloneDeep(this.options);
    this.hChartOptions.series[0].markLine.data = [
      {name: 'upper', yAxis: this.person.heartUp},
      {name: 'lower', yAxis: this.person.heartLow},
    ];
    this.hChartOptions.tooltip.formatter = (params) => {
      return new Date(params[0].data[0]).toLocaleString() + '<br>' + params[0].data[1] + ' ' + bSubtext;
    };

    this.moveChartOptions = _.cloneDeep(this.options);
    this.moveChartOptions.title.text = this.moveTitle;
    this.moveChartOptions.grid.y = '30px';
    this.moveChartOptions.series[0].type = 'bar';
    this.moveChartOptions.series[0].barWidth = '12px';
    this.moveChartOptions.series[0].itemStyle = {
      normal: {
        color: params => {
          let value = params.data[1];
          if (value < 5) {
            return 'green';
          } else if (value >= 5 && value <= 10) {
            return 'blue';
          } else if (value > 10 && value <= 15) {
            return 'orange';
          } else {
            return 'red';
          }
        }
      }
    };

    this.moveChartOptions.tooltip.formatter = (params) => {
      return new Date(params[0].data[0]).toLocaleString() + '<br>' + params[0].data[1] + ' ' + this.translate.get('moveUnit')['value'];
    };
    this.moveChartOptions.series[0].markLine.data = [{ yAxis: this.person.move}];
  }

  onBChartInit(ec) {
    this.bEchartsInstance = ec;
    ec.setOption(this.bChartOptions);
  }

  onHChartInit(ec) {
    this.hEchartsInstance = ec;
    ec.setOption(this.hChartOptions);
  }

  onMoveChartInit(ec) {
    this.moveChartsInstance = ec;
    this.moveChartsInstance.setOption(this.moveChartOptions);
  }

  buildEmptyData(startTime, endTime, step) {
    const data = [[startTime * 1000, ''], [endTime * 1000, '']];
    return data;
  }

  resetChartOptions() {
    if (this.bEchartsInstance) {
      this.bEchartsInstance.setOption(this.bChartOptions);
    }

    if (this.hEchartsInstance) {
      this.hEchartsInstance.setOption(this.bChartOptions);
    }

    if (this.moveChartsInstance) {
      this.moveChartsInstance.setOption(this.bChartOptions);
    }
  }

  initData() {
    // person status
    this.rest.get('/data/person/' + this.person.id).subscribe(data => {
      this.person = data;
    });

    // alarm counters
    this.rest.getWithParams('/api/pro/allAlarmCounters', {
      personId: this.person.id,
      interval: this.getSecondsFromLast8Am()
    }).subscribe(resp => {
      this.breatheAlarmTotal = resp['breatheAlarm'];
      this.heartAlarmTotal = resp['heartAlarm'];
      this.awayAlarmTotal = resp['awayAlarm'];
      this.wetAlarmTotal = resp['wetAlarm'];
      this.moveTotal = resp['move'];
    });

    const endTime = Math.round(new Date().getTime() / 1000);
    const startTime = endTime - 1 * 60 * 60;
    const step = 5;

    // breathe
    this.rest.getWithParams('/api/pro/counterRange', {
      counter: 'breathe',
      personId: this.person.id,
      startTime: startTime,
      endTime: endTime,
      step: step
    }).subscribe(resp => {
      if (!resp || !_.isArray(resp) || resp.length < 1) {
        this.bChartOptions.title.textStyle.color = 'darkblue';
        this.bChartOptions.series[0].data = this.buildEmptyData(startTime, endTime, step);
        this.bEchartsInstance.setOption(this.bChartOptions);
        return;
      }

      const data = resp;
      data.forEach(item => {
        item[0] = item[0] * 1000;
      });

      this.bChartOptions.series[0].data = data;
      this.breathe = data[data.length - 1][1];
      this.bEchartsInstance.setOption(this.bChartOptions);
    });

    // heart
    this.rest.getWithParams('/api/pro/counterRange', {
      counter: 'heart',
      personId: this.person.id,
      startTime: startTime,
      endTime: endTime,
      step: step
    }).subscribe(resp => {
      if (!resp || !_.isArray(resp) || resp.length < 1) {
        this.hChartOptions.series[0].data = this.buildEmptyData(startTime, endTime, step);
        this.hEchartsInstance.setOption(this.hChartOptions);
        return;
      }

      const data = resp;
      data.forEach(item => {
        item[0] = item[0] * 1000;
      });
      this.hChartOptions.series[0].data = data;
      this.heart = data[data.length - 1][1];
      this.hEchartsInstance.setOption(this.hChartOptions);
    });

    // move hist
    this.rest.getWithParams('/api/elastic/moves', {
      personId: this.person.id
    }).subscribe(resp => {
      this.moveChartOptions.series[0].markLine.data = [{ yAxis: this.person.move }];
      this.moveChartOptions.series[0].data = resp;
      this.moveChartsInstance.setOption(this.moveChartOptions);
    });

    // sleep, 5s for one data point
    const sleepIntervals = this.getSleepIntervals();
    const sleepStep = 5;
    this.rest.getWithParams('/api/pro/counterRange', {
      counter: 'sleep',
      personId: this.person.id,
      startTime: sleepIntervals[0],
      endTime: sleepIntervals[1],
      step: sleepStep
    }).subscribe(resp => {
      if (!resp || !_.isArray(resp) || resp.length < 1) {
        this.deepSleep = 0;
        this.shallowSleep = 0;
        this.sleepScore = 0;
        this.sleepDisplay = '- ';
        return;
      }

      this.deepSleep = 0;
      this.shallowSleep = 0;
      const data = resp;
      data.forEach(item => {
        if (item[1] === this.DEEP_SLEEP_MODE) {
          this.deepSleep++;
        } else if (item[1] === this.SHALLOW_SLEEP_MODE) {
          this.shallowSleep++;
        }
      });
      this.deepSleep = Math.round(this.deepSleep * 100 * sleepStep / 3600.0) / 100.0;
      this.shallowSleep = Math.round(this.shallowSleep * 100 * sleepStep / 3600.0) / 100.0;
      this.totalSleep = Math.round((this.deepSleep + this.shallowSleep) * 100) / 100.0;
      this.sleepCalculation();
    });
  }

  sleepCalculation() {
    const total = this.deepSleep + this.shallowSleep;
    if (this.deepSleep <= 0.1) {
      // If deep sleep is less than 6 minutes (0.1 hours), treat it as bad data
      this.sleepScore = 0;
    } else {
      const ratio = (this.deepSleep * 100.0) / total;
      if (ratio < 12.5) {
        this.sleepScore = 0;
      } else if (ratio >= 12.5 && ratio < 20) {
        this.sleepScore = Math.round(50 + ((80 - 50) / (20.0 - 12.5)) * (ratio - 12.5));
      } else if (ratio >= 20 && ratio < 22) {
        this.sleepScore = Math.round(80 + ((90 - 80) / (22.0 - 20.0)) * (ratio - 20.0));
      } else if (ratio >= 22 && ratio < 23) {
        this.sleepScore = Math.round(90 + ((95 - 90) / (23.0 - 22.0)) * (ratio - 22.0));
      } else if (ratio >= 23 && ratio < 25) {
        this.sleepScore = Math.round(95 + ((100 - 95) / (25.0 - 23.0)) * (ratio - 23.0));
      } else if (ratio >= 25) {
        this.sleepScore = 100;
      }
    }

    this.sleepDisplay = this.sleepScore;
    if (this.sleepScore >= 100) {
      this.sleepAdjustment = 'sleepPerfect';
    } else if ( this.sleepScore >= 95) {
      this.sleepAdjustment = 'sleepGood';
    } else if ( this.sleepScore >= 85) {
      this.sleepAdjustment = 'sleepNormal';
    } else if ( this.sleepScore >= 70) {
      this.sleepAdjustment = 'sleepFair';
    } else if ( this.sleepScore >= 60) {
      this.sleepAdjustment = 'sleepPass';
    } else {
      this.sleepAdjustment = 'sleepBelow';
      this.sleepDisplay = '< 50';
    }
  }

  getSleepColor() {
    if (this.sleepScore >= 100) {
      return 'secondary';
    } else if ( this.sleepScore >= 95) {
      return 'secondary';
    } else if ( this.sleepScore >= 85) {
      return 'primary';
    } else if ( this.sleepScore >= 70) {
      return 'primary';
    } else if ( this.sleepScore >= 60) {
      return 'primary';
    } else {
      return 'danger';
    }
  }

  startRoutine() {
    if (this.interval) {
      clearInterval(this.interval);
    }

    this.initChart();
    this.resetChartOptions();
    this.initData();

    this.interval = setInterval(() => {
      this.initData();
    }, 5000);
  }

  getSecondsFromLast8Am() {
    let hour = new Date().getHours();
    hour = hour >= 8 ? (hour - 8) : (24 + hour - 8);
    return hour * 60 * 60 + new Date().getMinutes() * 60 + new Date().getSeconds() - 1;
  }

  getSleepIntervals() {
    const times = [];
    let hour = new Date().getHours();
    const currentTime = Math.round(new Date().getTime() / 1000);
    if (hour >= 20) {
      const pastSecondsFrom8Pm = (hour - 20) * 60 * 60 + new Date().getMinutes() * 60 + new Date().getSeconds();
      const endTime = currentTime;
      const startTime = endTime - pastSecondsFrom8Pm;
      times.push(startTime);
      times.push(endTime);
      return times;
    } else if (hour < 20 && hour >= 8) {
      const endTime = currentTime - this.getSecondsFromLast8Am();
      const startTime = endTime - 12 * 60 * 60;
      times.push(startTime);
      times.push(endTime);
      return times;
    } else if (hour < 8){
      const pastSecondsFrom8Pm = (hour + 4) * 60 * 60 + new Date().getMinutes() * 60 + new Date().getSeconds();
      const endTime = currentTime;
      const startTime = endTime - pastSecondsFrom8Pm;
      times.push(startTime);
      times.push(endTime);
      return times;
    }
  }

  getBedImage() {
    if (this.person.awayAlarmFlag) {
      return "../../assets/imgs/leave.png";
    }

    if (this.person.upAlarmFlag) {
      return "../../assets/imgs/up.png";
    }

    if (this.person.sideAlarmFlag) {
      return "../../assets/imgs/side.png";
    }

    return "../../assets/imgs/sleep.png";
  }

  getBedAlarmStatus() {
    if (this.person.awayAlarm && this.person.awayAlarmFlag) {
      return 'danger';
    }

    if (this.person.upAlarm && this.person.upAlarmFlag) {
      return 'danger';
    }

    if (this.person.sideAlarm && this.person.sideAlarmFlag) {
      return 'danger';
    }

    return 'primary';
  }

  getBedAlarmString() {
    if (this.person.upAlarmFlag) {
      return this.translate.get('UP')['value'];
    } else if (this.person.sideAlarmFlag) {
      return this.translate.get('SIDE')['value'];
    } else if (this.person.awayAlarmFlag) {
      return this.translate.get('AWAY')['value'];
    } else {
      return this.translate.get('normal')['value'];
    }
  }

  getHeartAlarmStatus() {
    if (this.heart === '' || this.heart === '-') {
      return 'primary';
    }

    const currentValue = _.toNumber(this.heart);
    if (currentValue < this.person.heartLow || currentValue > this.person.heartUp) {
      return 'danger';
    }

    return 'primary';
  }

  getBreatheAlarmStatus() {
    if (this.breathe === '' || this.breathe === '-') {
      return 'primary';
    }

    const currentValue = _.toNumber(this.breathe);
    if (currentValue < this.person.breatheLow || currentValue > this.person.breatheUp) {
      return 'danger';
    }

    return 'primary';
  }

  getWetImage() {
    return this.person.wetAlarmFlag ? '../../assets/imgs/wet.png' : '../../assets/imgs/dry.png';
  }

  getWetAlarmStatus() {
    return this.person.wetAlarmFlag ? 'danger' : 'primary';
  }

  getWetAlarmString() {
    return this.person.wetAlarmFlag ? this.translate.get('wet')['value'] : this.translate.get('dry')['value'];
  }

  slideChanged() {
    const index = this.slides.getActiveIndex();
    if (index > -1 && index < this.persons.length) {
      this.person = this.persons[this.slides.getActiveIndex()];
      this.heart = '-';
      this.breathe = '-';
      this.startRoutine();
    }
  }

  nav2alarm(alarm) {
    this.navCtrl.push(AlarmPage, {
      person: this.person,
      alarm: alarm
    });
  }

  ionViewCanEnter(): boolean {
    return true;
  }

  ionViewDidEnter() {
    const index = _.findIndex(this.persons, this.person);
    const active = this.slides.getActiveIndex();
    if (index >= 0 && index !== active) {
      this.slides.slideTo(index);
    } else {
      this.startRoutine();
    }
  }

  ionViewWillLeave() {
    if (this.interval) {
      clearInterval(this.interval);
    }
  }

  navBack() {
    this.navCtrl.pop();
  }
}
